闲话 22.10.3

闲话

最近有一件事我比较在意。

某一日 EI 发了一个犇犇

众所周知,这是《四重罪孽》里的一句歌词

然后某些中V厨就按耐不住自己手头的歌词了
image
image

回想初二在家的那段时间
一套作业
带上耳机循环一天《妄想症》
的时光

让我现在还能唱一点四重罪孽

但是现在早就不记得词曲了 下次回家听听吧


夢の続きを知りたいのかい?

誰も見たこと無い絵本を

捲りなさい

それがあなたの

望む世界だとしよう

夢の終わりで眠ればいい

杂题

CF1605F

称一个长度为 n 的序列 aPalindORme 的,当且仅当对于任意 1in,满足 a1|a2||ai=an|an1||ani+1,其中 | 表示按位或运算。称一个长度为 n 的序列 bgood 的,当且仅当它可以重排成一个 PalindORme 的序列。

给你 n,k,m,求长度为 n,每个元素值域为 [0,2k) 的序列中有多少个是 good 的,对 m 取模。

n,k80

读题。读完了可以发现合法序列是关于中心对称的。具体地,从两边开始分别向中间镜像地拓展一个数,每次加入的二进制位是相同的。
然后刻画一下这个性质:
首先整一个计数器 V=0。每次选择这个序列两端的数 x,y,一定满足 x|V=y|V。赋 Vx|V,再把这两个数从序列中删除。

由于需要计数的串是重排之后的,因此对于 good 的序列,可以通过若干次操作变为长度不超过 1 的序列:
仍然是初始为 0 的计数器,每次选择一对任意位置的数 x,y 满足 x|V=y|V,赋 Vx|V,随后把这两个数删除。

对于不 good 的序列,定义它的最优子序列为通过上述操作移除的序列。可以发现在移除最优子序列后,不 good 的序列剩余元素都满足 xor V 不为 0 且之间两两不同。
因此一个不 good 的序列能够生成一个长度小于它的 good 的序列。

考虑一个套路容斥。
fi,j 表示长度为 i,二进制位数量为 j 的序列数,gi,j 表示长度为 i,二进制位数量为 j 的不合法序列数,hi,j 表示长度为 i,二进制位数量为 j ,内部元素均不为 0 且两两不同的序列数。

由定义,可以得到 fi,j 的计算方式:

fi,j=k=0j(1)jk(jk)(2k)i

hi,j 的计算式也可类似地得到:

hi,j=k=0j(1)jk(jk)(2k1)i_

然后可以枚举最优子序列长度和二进制位个数来得到 gi,j

gi,j=x=1iy=1j(ix)(jy)(2y)ix×hix,jy×(fx,ygx,y)

意义:我们首先钦定最优子序列的长度 x 和位数 y,这部分的总种类数是 (ix)(jy) 的。对于长度为 (ix) 的每个剩余元素,能任意填入最优子序列中已经存在的 y 位,这部分的总种类数是 (2y)ix 的。由于剩余元素都满足 xor V 不为 0 且之间两两不同,这部分的种类数是 hix,jy 的。最后考虑最优子序列的种类数,为 (fx,ygx,y)。求积再求和即为上式。

然后递推就完了。
总时间复杂度 O(n2k2)

code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 90 + 10;
int n, k, mod, pw[N * N], C[N][N], f[N][N], g[N][N], h[N][N], ans;

typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod;
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; }
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }

int L(int n, int m) { int ret = 1; rep(i,0,m-1) ret = mul(ret, n - i + mod); return ret; }

void init(int bnd) {
    Mod.init(mod);
    rep(i,0,bnd) C[i][0] = 1;
    pw[0] = 1;
    rep(i,1,bnd) {
        rep(j,1,i) C[i][j] = add(C[i-1][j-1], C[i-1][j]);
    } 
    rep(i,1,n*k) pw[i] = add(pw[i-1], pw[i-1]); 
}   

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> k >> mod;
    init(max(n, k));
    rep(i,0,n) rep(j,0,k) rep(l,0,j) {
        f[i][j] = add(f[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], pw[l * i]));
        h[i][j] = add(h[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], L(pw[l] - 1, i)));
    }
    rep(i,1,n) rep(j,1,k) rep(i2,0,i-1) rep(j2,0,j-1) 
        if ((n & 1) and (i == n) and (i2 == n-1)) continue;
        else g[i][j] = add(g[i][j], mul(C[i][i2], C[j][j2], pw[j2 * (i - i2)], h[i - i2][j - j2], f[i2][j2] + mod - g[i2][j2]));
    rep(i,0,k) ans = add(ans, mul(C[k][i], f[n][i] + mod - g[n][i]));
    cout << ans << endl;
}
posted @   joke3579  阅读(93)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示